package com.wyg.blog.filter;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.wyg.blog.config.RsaKeyProperties;
import com.wyg.blog.model.user.User;
import com.wyg.blog.service.user.UserService;
import com.wyg.blog.utils.JwtTokenUtil;
import com.wyg.blog.utils.MyAuthenticationException;
import com.wyg.blog.utils.RedisUtil;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.Map;

/**
 * @description:
 * @author: WYG
 * @time: 2020/6/22 16:58
 */

public class MyUsernamePasswordAuthenticationFilter extends UsernamePasswordAuthenticationFilter {
    private UserService userService;
    private AuthenticationManager authenticationManager;
    private RsaKeyProperties rsaKeyProperties;
    private RedisUtil redisUtil;

    public MyUsernamePasswordAuthenticationFilter(AuthenticationManager authenticationManager, UserService userService,
                                                  RsaKeyProperties rsaKeyProperties, RedisUtil redisUtil){
        this.authenticationManager = authenticationManager;
        this.userService = userService;
        this.rsaKeyProperties = rsaKeyProperties;
        this.redisUtil = redisUtil;
    }

    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
        try{
            ObjectMapper mapper = new ObjectMapper();
            Map<String,String> authenticationBean = mapper.readValue(request.getInputStream(), Map.class);
            String username = authenticationBean.get(SPRING_SECURITY_FORM_USERNAME_KEY);
            String password = authenticationBean.get(SPRING_SECURITY_FORM_PASSWORD_KEY);
            User user = userService.selectUserByUsername(username);
            BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();
            if(user == null) {
                throw new Exception("账号不存在，请检查");
            } else {
                String encoderPassword = user.getPassword();
                if(!bCryptPasswordEncoder.matches(password, encoderPassword)){
                    throw new Exception("密码不正确");
                }else {
                    UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(username,password);
                    setDetails(request,authRequest);
                    return authenticationManager.authenticate(authRequest);
                }
            }
        } catch (Exception e) {
            try {
                response.setContentType("application/json;charset=utf-8");
                response.setHeader("Access-Control-Allow-Origin", "*");
                response.setHeader("Access-Control-Allow-Method", "POST,GET");
                response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
                PrintWriter out = response.getWriter();
                Map resultMap = new HashMap();
                resultMap.put("code",HttpServletResponse.SC_UNAUTHORIZED);
                resultMap.put("msg",e.getMessage());
                out.write(new ObjectMapper().writeValueAsString(resultMap));
                out.flush();
                out.close();
            } catch (Exception exception) {
                exception.printStackTrace();
            }
            throw new MyAuthenticationException(e.getMessage());
        }
    }

    @Override
    protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authResult) throws IOException, ServletException {
        response.setHeader("Access-Control-Allow-Origin", "*");
        // 响应类型
        response.setHeader("Access-Control-Allow-Methods", "POST, GET, DELETE, OPTIONS, DELETE");
        // 响应头设置
        response.setHeader("Access-Control-Allow-Headers", "Content-Type, x-requested-with, X-Custom-Header, HaiYi-Access-Token");
        JwtTokenUtil jwtTokenUtil = new JwtTokenUtil();
        System.out.println("用户名是:"+authResult.getName());
        String token = null;
        if (redisUtil.hasKey(authResult.getName())) {
            token = redisUtil.get(authResult.getName()).toString();
        } else {
            token = jwtTokenUtil.generateToken(authResult.getName(),rsaKeyProperties.getPrivateKey());
            redisUtil.set(authResult.getName(), token, 60 * 2);
        }

        response.addHeader("Authorization","Bearer " + token);
        Integer uid = userService.selectUserByUsername(authResult.getName()).getId();
        try{
            response.setContentType("application/json;charset=utf-8");
            response.setStatus(HttpServletResponse.SC_OK);
            PrintWriter out = response.getWriter();
            Map resultMap = new HashMap();
            resultMap.put("code",HttpServletResponse.SC_OK);
            resultMap.put("msg","认证通过");
            resultMap.put("token",token);
            resultMap.put("uid",uid);
            out.write(new ObjectMapper().writeValueAsString(resultMap));
            out.flush();
            out.close();
        }catch (Exception outException){
            outException.printStackTrace();
        }
    }

    @Override
    protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, AuthenticationException failed) throws IOException, ServletException {
        Map<String,String> map = new HashMap<>();
        map.put("msg",failed.getMessage());
        map.put("code", "" + HttpServletResponse.SC_UNAUTHORIZED);
        response.setContentType("application/json;charset=utf-8");
        response.setHeader("Access-Control-Allow-Origin", "*");
        response.setHeader("Access-Control-Allow-Method", "POST,GET");
        PrintWriter out = response.getWriter();
        out.write(new ObjectMapper().writeValueAsString(map));
        out.flush();
        out.close();
    }
}
